#pragma once

#include <math.h>

#include "ConsoleWindow.h"

////////////////////////////////////////////////////////////////////////////////////////////////////
/// <Summary>	Vector2  </Summary>
/// 
/// <purpose>	Math utility to hold two floats in succesion	</purpose>
////////////////////////////////////////////////////////////////////////////////////////////////////

class Vector2
{
public:

	union
	{
		/// <Summary> arr: access to the floats as an array of two </Summary>
		float arr[2];

		struct
		{
			/// <Summary> The x coordinate </Summary>
			float x;
			/// <Summary> The y coordinate </Summary>
			float y;
		};

		struct
		{
			/// <Summary> The u component </Summary>
			float u;
			/// <Summary> The v component </Summary>
			float v;
		};
	};

public:

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Default constructor </Summary>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	Vector2() : x(0), y(0) { }

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Constructor </Summary>
	///
	/// <Param name="_x">	The x coordinate </Param>
	/// <Param name="_y">	The y coordinate </Param>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	Vector2(float _x, float _y)
		: x(_x), y(_y) { }

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Addition operator </Summary>
	///
	/// <Param name="vec">	The vector on the right side </Param>
	///
	/// <Return>	The result of the operation </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	inline Vector2 operator+(const Vector2& vec) const
	{
		return Vector2(x + vec.x, y + vec.y);
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Subtraction operator </Summary>
	///
	/// <Param name="vec">	The vector on the right side </Param>
	///
	/// <Return>	The result of the operation </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	inline Vector2 operator-(const Vector2& vec) const
	{
		return Vector2(x - vec.x, y - vec.y);
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Multiplication operator </Summary>
	///
	/// <Param name="vec">	The vector on the right side </Param>
	///
	/// <Return>	The result of the operation </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	inline Vector2 operator*(const Vector2& vec) const
	{
		return Vector2(x * vec.x, y * vec.y);
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Division operator </Summary>
	///
	/// <Param name="vec">	The vector on the right side </Param>
	///
	/// <Return>	The result of the operation </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	inline Vector2 operator/(const Vector2& vec) const
	{
		return Vector2(x / vec.x, y / vec.y);
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Multiplication operator </Summary>
	///
	/// <Param name="val">	The float on the right side </Param>
	///
	/// <Return>	The result of the operation </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	inline Vector2 operator*(float val) const
	{
		return Vector2(x * val, y * val);
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Division operator </Summary>
	///
	/// <Param name="val">	The float on the right side </Param>
	///
	/// <Return>	The result of the operation </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	inline Vector2 operator/(float val) const
	{
		return Vector2(x / val, y / val);
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Addition assignment operator </Summary>
	///
	/// <Param name="vec">	The vector on the right side </Param>
	///
	/// <Return>	The result of the operation as a reference </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	inline Vector2& operator+=(const Vector2& vec)
	{
		x += vec.x;
		y += vec.y;
		return *this;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Subtraction assignment operator </Summary>
	///
	/// <Param name="vec">	The vector on the right side </Param>
	///
	/// <Return>	The result of the operation as a reference </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	inline Vector2& operator-=(const Vector2& vec)
	{
		x -= vec.x;
		y -= vec.y;
		return *this;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Multiplication assignment operator </Summary>
	///
	/// <Param name="val">	The float on the right side </Param>
	///
	/// <Return>	The result of the operation as a reference </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	inline Vector2& operator*=(float val)
	{
		x *= val;
		y *= val;
		return *this;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Division assignment operator </Summary>
	///
	/// <Param name="val">	The float on the right side </Param>
	///
	/// <Return>	The result of the operation as a reference </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	inline Vector2& operator/=(float val)
	{
		x /= val;
		y /= val;
		return *this;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Makes the vector components all equal zero </Summary>
	///
	/// <Return>	This vector </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	inline Vector2& MakeZero()
	{
		x = y = 0;
		return *this;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Negates all of this vectors components </Summary>
	///
	/// <Return>	This vector </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	inline Vector2& Negate()
	{
		x = -x;
		y = -y;
		return *this;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Dot product </Summary>
	///
	/// <Param name="vec">	The vector on the right side </Param>
	///
	/// <Return>	Resulting value </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	inline float DotProduct(const Vector2& vec) const
	{
		return x * vec.x + y * vec.y;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Gets the magnitude of this vector </Summary>
	///
	/// <Return>	The magnitude </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	inline float Magnitude() const
	{
		return (float)sqrt(DotProduct(*this));
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Normalizes the current vector </Summary>
	///
	/// <Return>	This vector </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	inline Vector2& Normalize()
	{
		float invMag = 1 / Magnitude();
		*this *= invMag;
		return *this;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Multiplication operator </Summary>
	///
	/// <Param name="val">	The value on the left side </Param>
	/// <Param name="vec">	The value on the right side </Param>
	///
	/// <Return>	The result of the operation. </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	inline friend Vector2 operator*(float val, const Vector2& vec)
	{
		return Vector2(vec.x * val, vec.y * val);
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Division operator </Summary>
	///
	/// <Param name="val">	The value on the left side </Param>
	/// <Param name="vec">	The value on the right side </Param>
	///
	/// <Return>	The result of the operation. </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	inline friend Vector2 operator/(float val, const Vector2& vec)
	{
		return Vector2(vec.x / val, vec.y / val);
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Dot product </Summary>
	///
	/// <Param name="a">	The vector on the left side </Param>
	/// <Param name="b">	The vector on the right side </Param>
	///
	/// <Return>	Resulting value </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	inline friend float DotProduct(const Vector2& a, const Vector2& b)
	{
		return a.DotProduct(b);
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Interpolation </Summary>
	///
	/// <Param name="a">	 	The start vector </Param>
	/// <Param name="b">	 	The end vector </Param>
	/// <Param name="lambda">	The lambda </Param>
	///
	/// <Return>	The result </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	inline friend Vector2 Interpolate(const Vector2& a, const Vector2& b, float lambda)
	{
		return Vector2(a + ((b - a) * lambda));
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Prints this vector to the console </Summary>
	///
	/// <Param name="out">	The console window to write too </Param>
	/// <Param name="vec">	The vector to write out </Param>
	///
	/// <Return>	The console window </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	friend ConsoleWindow& operator<<(ConsoleWindow& out, const Vector2& vec)
	{
		out << "\nX = " << vec.x << " Y = " << vec.y << "\n";

		return out;
	}
};